﻿using System;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Reflection;
using System.Collections;
using System.Text;
using System.Web.UI.WebControls;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Net;
using Microsoft.Win32;

using LongNet.Config;
using LongNet.Util;
namespace LongNet.Web
{
    public static partial class WebUtils
    {
        #region Fields

        private static LongNet.Util.LogManager.Logger logger = LongNet.Util.LogManager.GetCurrentClassLogger();

        private static readonly Regex SlugTitleRegex = new Regex(@"&\w+;", RegexOptions.Compiled);
        private static readonly Regex StripHtmlRegex = new Regex("<[^>]*>", RegexOptions.Compiled);
        private static readonly Regex StripJavascriptRegex = new Regex("(<script[^>]*?>.*?</script>)", RegexOptions.IgnoreCase | RegexOptions.Singleline);

        private static readonly Regex ExtractTextFromHtmlRegex = new Regex(@"</?(?!br|/?p|img)[^>]*>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);

        #endregion

        #region Methods

        private static string CheckInput(string str)
        {
            str = str.Trim();
            if (string.IsNullOrEmpty(str))
            {
                return string.Empty;
            }
            str = Regex.Replace(str, "[\\s]{2,}", " ");	//两个或多个空格换成一个空格
            str = Regex.Replace(str, "(<[b|B][r|R]/*>)+|(<[p|P](.|\\n)*?>)", "\n");	//<br>
            str = Regex.Replace(str, "(\\s*&[n|N][b|B][s|S][p|P];\\s*)+", " ");	//&nbsp;
            str = Regex.Replace(str, "<(.|\\n)*?>", string.Empty);	//any other tags
            str = str.Replace("'", "''");
            return str;
        }


        /// <summary>
        /// Generates slug title form a title string.
        /// </summary>
        /// <param name="str">The string to generate flug title form.</param>
        /// <returns>The final slug title string.</returns>
        public static string SlugTitle(string str)
        {
            if (string.IsNullOrEmpty(str))
                return string.Empty;

            str = str.ToLower().Trim();
            str = SlugTitleRegex.Replace(str, string.Empty);

            char c;
            bool prevDash = false;
            var buffer = new StringBuilder(str.Length);

            for (int i = 0; i < str.Length; i++)
            {
                c = str[i];
                if (c == ' ' || c == ',' || c == '.' || c == '/' || c == '\\' || c == '-')
                {
                    if (!prevDash)
                    {
                        prevDash = true;
                        buffer.Append('-');
                    }
                }
                else if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
                {
                    buffer.Append(c);
                    prevDash = false;
                }

                if (i >= 255)
                    break;
            }

            str = buffer.ToString();

            // remove trailing dash, if there is one
            if (str.EndsWith("-"))
                str = str.Substring(0, str.Length - 1);

            return str;
        }


        /// <summary>
        /// Strips any html tags.
        /// </summary>
        /// <param name="str">The string to strip.</param>
        /// <returns>The striped string.</returns>
        public static string StripHtml(string str)
        {
            return StripHtmlRegex.Replace(str, string.Empty);
        }

        /// <summary>
        /// Strips javascript code and links.
        /// </summary>
        /// <param name="str">The string to strip.</param>
        /// <returns>The striped string.</returns>
        public static string StripJavascript(string str)
        {
            if (string.IsNullOrEmpty(str))
                return string.Empty;

            return StripJavascriptRegex.Replace(str, string.Empty);
        }

        /// <summary>
        /// Extracts text from html source reserving br,p,img items.
        /// </summary>
        /// <param name="str">The html source string.</param>
        /// <returns>The text string contains br,p,img items.</returns>
        public static string ExtractTextFromHtml(string str)
        {
            return ExtractTextFromHtmlRegex.Replace(str, string.Empty);
        }

        #endregion

        #region Fileds

        private static readonly string[] BrowserNames = { "ie", "opera", "netscape", "mozilla", "konqueror", "firefox" };
        private static readonly string[] SearchEngines = { "google", "yahoo", "msn", "baidu", "sogou", "sohu", "sina", "163", "lycos", "tom", "yisou", "iask", "soso", "gougou", "zhongsou" };

        private static readonly Regex MobileRegex = new Regex(@"(nokia|sonyericsson|blackberry|samsung|sec\-|windows ce|motorola|mot\-|up.b|midp\-)", RegexOptions.IgnoreCase | RegexOptions.Compiled);

        #endregion

        #region Utils

        /// <summary>
        /// Gets a bool value indicating whether gets a http get request or not.
        /// </summary>
        public static bool IsGet
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return false;

                return context.Request.HttpMethod.Equals("GET");
            }
        }

        /// <summary>
        /// Gets a bool value indicating whether gets a http post request or not.
        /// </summary>
        public static bool IsPost
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return false;

                return context.Request.HttpMethod.Equals("POST");
            }
        }

        /// <summary>
        /// Gets a value indicating whether the client is a mobile device.
        /// </summary>
        public static bool IsFromMobile
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return false;

                var request = context.Request;

                if (request.Browser.IsMobileDevice)
                    return true;

                if (!string.IsNullOrEmpty(request.UserAgent) && MobileRegex.IsMatch(request.UserAgent))
                    return true;

                return false;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the client is a browser or not.
        /// </summary>
        public static bool IsFromBrowser
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return false;

                return LongNet.Util.Utils.InStringArray(context.Request.Browser.Type.ToLower(), BrowserNames);
            }
        }

        /// <summary>
        /// Gets a value indicating whether the client is from a search engine or not.
        /// </summary>
        public static bool IsFromSearchEngine
        {
            get
            {
                return LongNet.Util.Utils.InStringArray(ReferrerUrl.ToLower(), SearchEngines);
            }
        }


        /// <summary>
        /// Gets the current request url.
        /// </summary>
        public static string Url
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return string.Empty;

                return context.Request.Url.ToString();
            }
        }

        /// <summary>
        /// Gets the current request raw url.
        /// </summary>
        public static string RawUrl
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return string.Empty;

                return context.Request.RawUrl;
            }
        }

        /// <summary>
        /// Gets the last request url(referrer url).
        /// </summary>
        public static string ReferrerUrl
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return string.Empty;

                var referrer = context.Request.UrlReferrer;
                return referrer == null ? string.Empty : referrer.ToString();
            }
        }

        /// <summary>
        /// Gets the absolute path of request url.
        /// </summary>
        public static string AbsolutePath
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return string.Empty;

                return context.Request.Url.AbsolutePath;
            }
        }

        /// <summary>
        /// Gets the page name of current request url.
        /// </summary>
        public static string PageName
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return string.Empty;

                string path = context.Request.Url.AbsolutePath;
                return path.Substring(path.LastIndexOf('/') + 1);
            }
        }

        /// <summary>
        /// Gets the host of current request url.
        /// </summary>
        public static string Host
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return string.Empty;

                return context.Request.Url.Host;
            }
        }

        /// <summary>
        /// Gets the full host of current request url.
        /// </summary>
        public static string FullHost
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return string.Empty;

                var url = context.Request.Url;

                if (url.IsDefaultPort)
                    return url.Host;

                return string.Format("{0}:{1}", url.Host, url.Port.ToString());
            }
        }

        /// <summary>
        /// Gets the application path of current ASP.NET application.
        /// </summary>
        public static string ApplicationPath
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return string.Empty;

                return context.Request.ApplicationPath;
            }
        }

        /// <summary>
        /// Gets the physical application path of current ASP.NET application.
        /// </summary>
        public static string PhysicalApplicationPath
        {
            get
            {
                var context = HttpContext.Current;

                if (context == null)
                    return string.Empty;

                return context.Request.PhysicalApplicationPath;
            }
        }

        /// <summary>
        /// Gets the server variable value name of current request.
        /// </summary>
        /// <param name="name">The string key of the entry to locate. The key can be null.</param>
        public static string ServerVariable(string name)
        {
            var context = HttpContext.Current;

            if (context == null)
                return string.Empty;

            return context.Request.ServerVariables[name] ?? string.Empty;
        }

        /// <summary>
        /// Gets the file name(with extension) of a specified url.
        /// </summary>
        /// <param name="url">The url to get file name from.</param>
        /// <returns>The file name string.</returns>
        public static string UrlFileName(string url)
        {
            if (string.IsNullOrEmpty(url))
                return string.Empty;

            string[] arr = url.Replace("\\", "/").Split('/');
            return arr[arr.Length - 1].Split('?')[0];
        }

        #endregion

        #region Request Params

        /// <summary>
        /// Gets the request param count.
        /// </summary>
        public static int ParamCount
        {
            get
            {
                return FormCount + QueryCount;
            }
        }

        /// <summary>
        /// Gets the request form count.
        /// </summary>
        public static int FormCount
        {
            get
            {
                return HttpContext.Current == null ? 0 : HttpContext.Current.Request.Form.Count;
            }
        }

        /// <summary>
        /// Gets the request query count.
        /// </summary>
        public static int QueryCount
        {
            get
            {
                return HttpContext.Current == null ? 0 : HttpContext.Current.Request.QueryString.Count;
            }
        }

        /// <summary>
        /// Gets the request param string value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static string ParamString(string name)
        {
            string value = QueryString(name);
            return value == string.Empty ? FormString(name) : value;
        }

        /// <summary>
        /// Gets the request query string value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static string QueryString(string name)
        {
            object val = HttpContext.Current.Request.QueryString[name];
            return val == null ? string.Empty : val.ToString();
        }

        /// <summary>
        /// Gets the request form string value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static string FormString(string name)
        {
            object value = HttpContext.Current.Request.Form[name];
            return value == null ? string.Empty : value.ToString();
        }


        /// <summary>
        /// Gets the request form byte value by the specified name. 
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static byte ParamByte(string name)
        {
            return LongNet.Util.Utils.StringToByte(ParamString(name), 0);
        }
        /// <summary>
        /// Gets the request form byte value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static byte ParamByte(string name, byte defaultValue)
        {
            return LongNet.Util.Utils.StringToByte(ParamString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request query byte value by the specified name. 
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static byte QueryByte(string name)
        {
            return LongNet.Util.Utils.StringToByte(QueryString(name), 0);
        }
        /// <summary>
        /// Gets the request query byte value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static byte QueryByte(string name, byte defaultValue)
        {
            return LongNet.Util.Utils.StringToByte(QueryString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request form byte value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static byte FormByte(string name)
        {
            return LongNet.Util.Utils.StringToByte(FormString(name), 0);
        }
        /// <summary>
        /// Gets the request form byte value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static byte FormByte(string name, byte defaultValue)
        {
            return LongNet.Util.Utils.StringToByte(FormString(name), defaultValue);
        }


        /// <summary>
        /// Gets the request param int value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static int ParamInt(string name)
        {
            return LongNet.Util.Utils.StringToInt(ParamString(name), 0);
        }
        /// <summary>
        /// Gets the request param int value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static int ParamInt(string name, int defaultValue)
        {
            return LongNet.Util.Utils.StringToInt(ParamString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request query int value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static int QueryInt(string name)
        {
            return LongNet.Util.Utils.StringToInt(QueryString(name), 0);
        }
        /// <summary>
        /// Gets the request query int value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static int QueryInt(string name, int defaultValue)
        {
            return LongNet.Util.Utils.StringToInt(QueryString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request form int value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static int FormInt(string name)
        {
            return LongNet.Util.Utils.StringToInt(FormString(name), 0);
        }
        /// <summary>
        /// Gets the request form int value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static int FormInt(string name, int defaultValue)
        {
            return LongNet.Util.Utils.StringToInt(FormString(name), defaultValue);
        }


        /// <summary>
        /// Gets the request param long value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static long ParamLong(string name)
        {
            return LongNet.Util.Utils.StringToLong(ParamString(name), 0);
        }
        /// <summary>
        /// Gets the request param long value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static long ParamLong(string name, long defaultValue)
        {
            return LongNet.Util.Utils.StringToLong(ParamString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request query long value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static long QueryLong(string name)
        {
            return LongNet.Util.Utils.StringToLong(QueryString(name), 0);
        }
        /// <summary>
        /// Gets the request query long value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static long QueryLong(string name, long defaultValue)
        {
            return LongNet.Util.Utils.StringToLong(QueryString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request form long value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static long FormLong(string name)
        {
            return LongNet.Util.Utils.StringToLong(FormString(name), 0);
        }
        /// <summary>
        /// Gets the request form long value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static long FormLong(string name, long defaultValue)
        {
            return LongNet.Util.Utils.StringToLong(FormString(name), defaultValue);
        }


        /// <summary>
        /// Gets the request param float value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static float ParamFloat(string name)
        {
            return LongNet.Util.Utils.StringToFloat(ParamString(name), 0F);
        }
        /// <summary>
        /// Gets the request param float value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static float ParamFloat(string name, float defaultValue)
        {
            return LongNet.Util.Utils.StringToFloat(ParamString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request query float value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static float QueryFloat(string name)
        {
            return LongNet.Util.Utils.StringToFloat(QueryString(name), 0F);
        }
        /// <summary>
        /// Gets the request query float value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static float QueryFloat(string name, float defaultValue)
        {
            return LongNet.Util.Utils.StringToFloat(QueryString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request form float value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static float FormFloat(string name)
        {
            return LongNet.Util.Utils.StringToFloat(FormString(name), 0F);
        }
        /// <summary>
        /// Gets the request form float value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static float FormFloat(string name, float defaultValue)
        {
            return LongNet.Util.Utils.StringToFloat(FormString(name), defaultValue);
        }


        /// <summary>
        /// Gets the request param decimal value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static decimal ParamDecimal(string name)
        {
            return LongNet.Util.Utils.StringToDecimal(ParamString(name), 0M);
        }
        /// <summary>
        /// Gets the request param decimal value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static decimal ParamDecimal(string name, decimal defaultValue)
        {
            return LongNet.Util.Utils.StringToDecimal(ParamString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request query decimal value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static decimal QueryDecimal(string name)
        {
            return LongNet.Util.Utils.StringToDecimal(QueryString(name), 0M);
        }
        /// <summary>
        /// Gets the request query decimal value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static decimal QueryDecimal(string name, decimal defaultValue)
        {
            return LongNet.Util.Utils.StringToDecimal(QueryString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request form decimal value by the specified name.
        /// If the request name does not exist, 0 will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static decimal FormDecimal(string name)
        {
            return LongNet.Util.Utils.StringToDecimal(FormString(name), 0M);
        }
        /// <summary>
        /// Gets the request form decimal value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static decimal FormDecimal(string name, decimal defaultValue)
        {
            return LongNet.Util.Utils.StringToDecimal(FormString(name), defaultValue);
        }


        /// <summary>
        /// Gets the request param bool value by the specified name.
        /// If the request name does not exist, false will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static bool ParamBool(string name)
        {
            return LongNet.Util.Utils.StringToBool(ParamString(name), false);
        }
        /// <summary>
        /// Gets the request param bool value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static bool ParamBool(string name, bool defaultValue)
        {
            return LongNet.Util.Utils.StringToBool(ParamString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request query bool value by the specified name.
        /// If the request name does not exist, false will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static bool QueryBool(string name)
        {
            return LongNet.Util.Utils.StringToBool(QueryString(name), false);
        }
        /// <summary>
        /// Gets the request query bool value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static bool QueryBool(string name, bool defaultValue)
        {
            return LongNet.Util.Utils.StringToBool(QueryString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request form bool value by the specified name.
        /// If the request name does not exist, false will be returned.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <returns>The request value.</returns>
        public static bool FormBool(string name)
        {
            return LongNet.Util.Utils.StringToBool(FormString(name), false);
        }
        /// <summary>
        /// Gets the request form bool value by the specified name.
        /// </summary>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static bool FormBool(string name, bool defaultValue)
        {
            return LongNet.Util.Utils.StringToBool(FormString(name), defaultValue);
        }

        /// <summary>
        /// Gets the request param enum value by the specified name, ignore case.
        /// If the request name does not exist, false will be returned.
        /// </summary>
        /// <typeparam name="T">An enum type.</typeparam>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static T ParamEnum<T>(string name, T defaultValue)
        {
            return LongNet.Util.Utils.StringToEnum(ParamString(name), defaultValue, true);
        }
        /// <summary>
        /// Gets the request param enum value by the specified name.
        /// If the request name does not exist, false will be returned.
        /// </summary>
        /// <typeparam name="T">An enum type.</typeparam>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <param name="ignoreCase">If true, ignore case; otherwise, regard case.</param>
        /// <returns>The request value.</returns>
        public static T ParamEnum<T>(string name, T defaultValue, bool ignoreCase)
        {
            return LongNet.Util.Utils.StringToEnum(ParamString(name), defaultValue, ignoreCase);
        }

        /// <summary>
        /// Gets the request query enum value by the specified name, ignore case.
        /// If the request name does not exist, false will be returned.
        /// </summary>
        /// <typeparam name="T">An enum type.</typeparam>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static T QueryEnum<T>(string name, T defaultValue)
        {
            return LongNet.Util.Utils.StringToEnum(QueryString(name), defaultValue, true);
        }
        /// <summary>
        /// Gets the request query enum value by the specified name.
        /// If the request name does not exist, false will be returned.
        /// </summary>
        /// <typeparam name="T">An enum type.</typeparam>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <param name="ignoreCase">If true, ignore case; otherwise, regard case.</param>
        /// <returns>The request value.</returns>
        public static T QueryEnum<T>(string name, T defaultValue, bool ignoreCase)
        {
            return LongNet.Util.Utils.StringToEnum(QueryString(name), defaultValue, ignoreCase);
        }

        /// <summary>
        /// Gets the request form enum value by the specified name, ignore case.
        /// If the request name does not exist, false will be returned.
        /// </summary>
        /// <typeparam name="T">An enum type.</typeparam>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <returns>The request value.</returns>
        public static T FormEnum<T>(string name, T defaultValue)
        {
            return LongNet.Util.Utils.StringToEnum(FormString(name), defaultValue, true);
        }
        /// <summary>
        /// Gets the request form enum value by the specified name.
        /// If the request name does not exist, false will be returned.
        /// </summary>
        /// <typeparam name="T">An enum type.</typeparam>
        /// <param name="name">The param name to search.</param>
        /// <param name="defaultValue">If the request name does not exist, defaultValue will be returned.</param>
        /// <param name="ignoreCase">If true, ignore case; otherwise, regard case.</param>
        /// <returns>The request value.</returns>
        public static T FormEnum<T>(string name, T defaultValue, bool ignoreCase)
        {
            return LongNet.Util.Utils.StringToEnum(FormString(name), defaultValue, ignoreCase);
        }

        #endregion

        #region Url/IpAddress

        /// <summary>
        /// Indicates whether the specified string is in url format.
        /// </summary>
        /// <param name="url">A url string.</param>
        /// <returns>True if in url format, false otherwise.</returns>
        public static bool IsUrl(string url)
        {
            return LongNet.Util.Utils.IsUrl(url);
        }

        /// <summary> 
        /// Gets the request ip address.
        /// </summary> 
        public static string IpAddress
        {
            get
            {
                string ip = ServerVariable("HTTP_X_FORWARDED_FOR");
                if (string.IsNullOrEmpty(ip))
                    ip = ServerVariable("REMOTE_ADDR");

                //if (string.IsNullOrEmpty(ip))
                //    LongNet.Util.Utils.DoTryCatch(() => { ip = HttpContext.Current.Request.UserHostAddress; });

                if (string.IsNullOrEmpty(ip) || !IsIpAddress(ip))
                    ip = "0.0.0.0";

                return ip;
            }
        }

        /// <summary>
        /// Indicates whether the specified string is in ip format.
        /// </summary>
        /// <param name="ipAddress">An ip string.</param>
        /// <returns>True if in ip format, false otherwise.</returns>
        public static bool IsIpAddress(string ipAddress)
        {
            return LongNet.Util.Utils.IsIpAddress(ipAddress);
        }

        /// <summary>
        /// Gets a bool value indicating whether the given ip is in the specified ip array or not.
        /// The ips in ip array can use * to represent any ip section (e.g. 192.168.1.*).
        /// </summary>
        /// <param name="ip">The ip to check.</param>
        /// <param name="ipArray">A ip array to check with.</param>
        /// <returns>True if in array, false otherwise.</returns>
        public static bool InIpAddressArray(string ip, params string[] ipArray)
        {
            string[] ips = ip.Split('.');
            for (int index = 0; index < ips.Length; index++)
            {
                string[] tempIps = ipArray[index].Split('.');
                int r = 0;
                for (int i = 0; i < tempIps.Length; i++)
                {
                    if (tempIps[i] == "*")
                        return true;

                    if (ips.Length > i)
                    {
                        if (tempIps[i] == ips[i])
                            r++;
                        else
                            break;
                    }
                    else
                    {
                        break;
                    }
                }

                if (r == 4)
                    return true;
            }

            return false;
        }

        #endregion

        #region ReturnHttpStatus/ClientRedirect

        /*
         * 200 OK 
         * 301 Moved Permanently
         * 302 Found 
         * 304 Not Modified 
         * 307 Temporary Redirect 
         * 400 Bad Request 
         * 401 Unauthorized 
         * 403 Forbidden 
         * 404 Not Found
         * 410 Gone 
         * 500 Internal Server Error
         * 501 Not Implemented
         */

        /// <summary>
        /// Returns 404 status and ends current request.
        /// </summary>
        public static void ReturnHttp404()
        {
            ReturnHttpStatus(404);
        }

        /// <summary>
        /// Returns HTTP status code and ends current request.
        /// </summary>
        /// <param name="statusCode">The <see cref="T:HttpStatusCode"/> returned to the client.</param>
        public static void ReturnHttpStatus(HttpStatusCode statusCode)
        {
            ReturnHttpStatus((int)statusCode);
        }

        /// <summary>
        /// Returns HTTP status code and ends current request.
        /// </summary>
        /// <param name="statusCode">The HTTP status code returned to the client.</param>
        public static void ReturnHttpStatus(int statusCode)
        {
            HttpContext context = HttpContext.Current;

            if (context != null)
            {
                context.Response.Clear();
                context.Response.ClearContent();
                context.Response.StatusCode = statusCode;
                context.Response.SuppressContent = true;
                context.Response.End();
            }
        }


        /// <summary>
        /// Replaces a url in top window and ends current request.
        /// </summary>
        /// <param name="url">The url to replace with.</param>
        public static void ClientRedirect(string url)
        {
            ClientRedirect(url, false/*topWindow*/, true/*replace*/);
        }

        /// <summary>
        /// Replaces a url and ends current request.
        /// </summary>
        /// <param name="url">The url to replace with.</param>
        /// <param name="topWindow">True if replace in top window, false otherwise.</param>
        public static void ClientRedirect(string url, bool topWindow)
        {
            ClientRedirect(url, topWindow, true/*replace*/);
        }

        /// <summary>
        /// Replaces a url.
        /// </summary>
        /// <param name="url">The url to replace with.</param>
        /// <param name="topWindow">True if replace in top window, false otherwise.</param>
        /// <param name="replace">True if replaces the location, false otherwise.</param>
        public static void ClientRedirect(string url, bool topWindow, bool replace)
        {
            url.ThrowsIfNullOrEmpty("url");

            HttpContext context = HttpContext.Current;

            if (context != null)
            {
                context.Response.Clear();
                context.Response.ClearContent();

                var html = @"
<html>
	<head>
		<meta http-equiv=""Content-Type"" content=""text/html; charset=utf-8"" />
	</head>
	<body>
		{0}
	</body>
</html>";

                var script = string.Empty;
                if (replace == false)
                    script = string.Format("<script language=\"javascript\" type=\"text/javascript\">{0}location.href = \"{1}\";</script>", topWindow ? "top." : string.Empty, url);
                else
                    script = string.Format("<script language=\"javascript\" type=\"text/javascript\">if({0}location.href==\"{1}\") {0}location=\"{1}\"; else {0}location.replace(\"{1}\");</script>", topWindow ? "top." : string.Empty, url);

                context.Response.Write(string.Format(html, script));
                context.Response.End();
            }
        }

        #endregion

        #region TransferHtml/ResponseFile/TransmitFile

        /// <summary>
        /// Transfer a page in the ASP.NET server to a static html file.
        /// </summary>
        /// <param name="path">The path of the page to transfer.</param>
        /// <param name="htmlPath">the path to save static html file.</param>
        public static void TransferHtml(string path, string htmlPath)
        {
            Page page = new Page();

            using (var writer = new StringWriter())
            {
                page.Server.Execute(path, writer);
                using (var fs = File.Create(LongNet.Util.Utils.GetFullPath(htmlPath)))
                {
                    byte[] buffer = Encoding.UTF8.GetBytes(writer.ToString());
                    fs.Write(buffer, 0, buffer.Length);
                    fs.Close();
                }
            }
        }

        /// <summary>
        /// Responses a file to the client.
        /// </summary>
        /// <param name="filePath">The path of the file.</param>
        public static void ResponseFile(string filePath)
        {
            if (filePath == null || filePath.Length == 0)
                throw new ArgumentException("The filePath is null or empty.", "filePath");

            ResponseFile(filePath, Path.GetFileName(filePath), LongNet.Util.Utils.GetContentType(filePath));
        }

        /// <summary>
        /// Responses a file to the client.
        /// </summary>
        /// <param name="filePath">The path of the file.</param>
        /// <param name="contentType">The content type of the file.</param>
        public static void ResponseFile(string filePath, string contentType)
        {
            if (filePath == null || filePath.Length == 0)
                throw new ArgumentException("The filePath is null or empty.", "filePath");

            ResponseFile(filePath, Path.GetFileName(filePath), contentType);
        }

        /// <summary>
        /// Responses a file to the client.
        /// </summary>
        /// <param name="filePath">The path of the file.</param>
        /// <param name="fileName">The output file name to client.</param>
        /// <param name="contentType">The content type of the file.</param>
        public static void ResponseFile(string filePath, string fileName, string contentType)
        {
            if (filePath == null || filePath.Length == 0)
                throw new ArgumentException("The filePath is null or empty.", "filePath");

            using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                ResponseFile(stream, fileName, contentType);
                stream.Close();
            }
        }

        /// <summary>
        /// Responses a file stream to the client.
        /// </summary>
        /// <param name="fileStream">The stream of a file.</param>
        /// <param name="fileName">The output file name to client.</param>
        /// <param name="contentType">The content type of the file.</param>
        public static void ResponseFile(Stream fileStream, string fileName, string contentType)
        {
            if (fileStream == null)
                throw new ArgumentNullException("fileStream", "The fileStream is null.");
            if (fileName == null || fileName.Length == 0)
                throw new ArgumentException("The fileName is null or empty.", "fileName");

            HttpContext context = HttpContext.Current;
            if (context != null)
            {
                try
                {
                    context.Response.Clear();
                    context.Response.ClearContent();
                    context.Response.ClearHeaders();
                    context.Response.ContentType = contentType;
                    context.Response.AddHeader("Content-Disposition", "attachment;filename=" + LongNet.Util.Utils.UrlEncode(fileName.Trim()).Replace("+", " "));

                    if (context.Response.IsClientConnected)
                    {
                        int size = 0, blockSize = 10240;
                        byte[] buffer = new byte[blockSize];
                        do
                        {
                            size = fileStream.Read(buffer, 0, blockSize);
                            if (size > 0)
                            {
                                context.Response.OutputStream.Write(buffer, 0, size);
                                context.Response.Flush();
                            }
                        }
                        while (size > 0 && context.Response.IsClientConnected);
                    }
                    context.Response.End();
                }
                catch (Exception ex)
                {
                    if (logger.IsErrorEnabled)
                        logger.Error("Fail to response file : {0}, content type: {1}", fileName, contentType);

                    context.Response.Write("Error : " + ex.Message);
                }
            }
        }


        /// <summary>
        /// Transmits a file to the client.
        /// </summary>
        /// <param name="filePath">The path of the file.</param>
        public static void TransmitFile(string filePath)
        {
            if (filePath == null || filePath.Length == 0)
                throw new ArgumentException("The filePath is null or empty.", "filePath");

            TransmitFile(filePath, Path.GetFileName(filePath), LongNet.Util.Utils.GetContentType(filePath));
        }

        /// <summary>
        /// Transmits a file to the client.
        /// </summary>
        /// <param name="filePath">The path of the file.</param>
        /// <param name="contentType">The content type of the file.</param>
        public static void TransmitFile(string filePath, string contentType)
        {
            if (filePath == null || filePath.Length == 0)
                throw new ArgumentException("The filePath is null or empty.", "filePath");

            TransmitFile(filePath, Path.GetFileName(filePath), contentType);
        }

        /// <summary>
        /// Transmits a file to the client.
        /// </summary>
        /// <param name="filePath">The path of the file.</param>
        /// <param name="fileName">The output file name to client.</param>
        /// <param name="contentType">The content type of the file.</param>
        public static void TransmitFile(string filePath, string fileName, string contentType)
        {
            filePath.ThrowsIfNullOrEmpty("filePath", "The filePath is null or empty.");
            fileName.ThrowsIfNullOrEmpty("fileName", "The fileName is null or empty.");

            HttpContext context = HttpContext.Current;
            if (context != null)
            {
                try
                {
                    context.Response.Clear();
                    context.Response.ClearContent();
                    context.Response.ClearHeaders();
                    context.Response.ContentType = contentType;
                    context.Response.AddHeader("Content-Disposition", "attachment;filename=" + LongNet.Util.Utils.UrlEncode(fileName.Trim()).Replace("+", " "));

                    context.Response.TransmitFile(filePath);
                    context.Response.End();
                }
                catch (Exception ex)
                {
                    if (logger.IsErrorEnabled)
                        logger.Error("Fail to response file : {0}, content type: {1}", fileName, contentType);

                    context.Response.Write("Error : " + ex.Message);
                }
            }
        }

        #endregion

        #region Fields

        private const string HighlightKeywordsFormat = "<font color=\"red\">{0}</font>";
        private static readonly string[] RegexHighlightKeywordsTagReal = new string[] { "<font color=\"red\">", "</font>" };
        private static readonly string[] RegexHighlightKeywordsTagTemp = new string[] { Guid.NewGuid().ToString(), Guid.NewGuid().ToString() };

        #endregion

        #region Methods

        /// <summary>
        /// Highlights the keywords in the text using the tag format string 
        /// "&lt;font color='red'&gt;{0}&lt;/font&gt;", ignore Case.
        /// </summary>
        /// <param name="text">A text string.</param>
        /// <param name="keywords">The keywords.</param>
        /// <returns>The resolved text string.</returns>
        public static string HighlightKeywords(string text, params string[] keywords)
        {
            return SmartFilter.FormatKeys(text, HighlightKeywordsFormat, true, keywords);
        }

        /// <summary>
        /// Highlights the keywords in the text using the tag format string 
        /// "&lt;font color='red'&gt;{0}&lt;/font&gt;".
        /// </summary>
        /// <param name="text">A text string.</param>
        /// <param name="ignoreCase">Whether ignore case or not.</param>
        /// <param name="keywords">The keywords.</param>
        /// <returns>The resolved text string.</returns>
        public static string HighlightKeywords(string text, bool ignoreCase, params string[] keywords)
        {
            return SmartFilter.FormatKeys(text, HighlightKeywordsFormat, ignoreCase, keywords);
        }


        /// <summary>
        /// Highlights the keywords in the text using the tag format string 
        /// "&lt;font color='red'&gt;{0}&lt;/font&gt;".
        /// </summary>
        /// <param name="text">A text string.</param>
        /// <param name="ignoreCase">Whether ignore case or not.</param>
        /// <param name="keywords">The keywords.</param>
        /// <returns>The resolved text string.</returns>
        public static string RegexHighlightKeywords(string text, bool ignoreCase, params string[] keywords)
        {
            // 这个版本不够快

            if (keywords == null || keywords.Length == 0)
                return text;

            StringBuilder sb = new StringBuilder(text);

            for (int i = 0; i < keywords.Length; i++)
            {
                if (RegexHighlightKeywordsTagTemp[0].IndexOf(keywords[i]) > -1
                    || RegexHighlightKeywordsTagTemp[1].IndexOf(keywords[i]) > -1)
                    continue;

                MatchCollection mc = Regex.Matches(sb.ToString(), Regex.Escape(keywords[i]), ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None);
                //循环在匹配的子串前后插入字符
                for (int j = 0; j < mc.Count; j++)
                {
                    //temp[1].Length为插入html标签使revl字符串增加的长度:
                    int len = RegexHighlightKeywordsTagTemp[0].Length + RegexHighlightKeywordsTagTemp[1].Length;
                    sb.Insert(mc[j].Index + keywords[i].Length + j * len, RegexHighlightKeywordsTagTemp[1]);//关键字后插入html标签
                    sb.Insert(mc[j].Index + j * len, RegexHighlightKeywordsTagTemp[0]);//关键字前插入html标签
                }
            }

            //还原插入字符串
            sb = sb
                .Replace(RegexHighlightKeywordsTagTemp[0], RegexHighlightKeywordsTagReal[0])
                .Replace(RegexHighlightKeywordsTagTemp[1], RegexHighlightKeywordsTagReal[1]);

            return sb.ToString();
        }

        #endregion

        /// <summary>
        /// Finds a web control by id in the specified container.
        /// </summary>
        /// <param name="container">The container to find from.</param>
        /// <param name="id">The id of the web control to find.</param>
        /// <returns>The web control found, null otherwise.</returns>
        public static Control FindWebControl(Control container, string id)
        {
            if ((container == null) || string.IsNullOrEmpty(id))
                return null;

            if (!(container is INamingContainer) && (container.NamingContainer != null))
                container = container.NamingContainer;

            Control control = FindWebControlInternal(container, id, null);
            if (control == null)
            {
                Dictionary<Control, bool> dictionary = new Dictionary<Control, bool>();
                dictionary[container] = true;
                container = container.NamingContainer;
                while ((container != null) && (control == null))
                {
                    control = FindWebControlInternal(container, id, dictionary);
                    dictionary[container] = true;
                    container = container.NamingContainer;
                }
            }

            return control;
        }

        private static Control FindWebControlInternal(Control control, string id, Dictionary<Control, bool> dictionary)
        {
            if (control.ID == id)
                return control;

            Control fControl = control.FindControl(id);
            if ((fControl != null) && (fControl.ID == id))
                return fControl;

            foreach (Control ctl in control.Controls)
            {
                if ((dictionary == null) || !dictionary.ContainsKey(ctl))
                {
                    fControl = FindWebControlInternal(ctl, id, dictionary);
                    if (fControl != null)
                        return fControl;
                }
            }

            return null;
        }

        /// <summary>
        /// Gets an int id list from the selected CheckBox in the Repeater control.
        /// </summary>
        /// <param name="repeater">The Repeater control.</param>
        /// <param name="checkBoxId">The id of the CheckBox control in the Repeater.</param>
        /// <param name="hiddenFieldId">The id of the HiddenField control in the Repeater which value is related with the CheckBox control.</param>
        /// <returns>An int id list.</returns>
        public static List<int> GetRepeaterSelectedIntId(Repeater repeater, string checkBoxId, string hiddenFieldId)
        {
            List<int> list = new List<int>();
            foreach (RepeaterItem item in repeater.Items)
            {
                CheckBox checkBox = item.FindControl(checkBoxId) as CheckBox;
                if (checkBox != null && checkBox.Checked)
                {
                    HiddenField hiddenField = item.FindControl(hiddenFieldId) as HiddenField;
                    if (hiddenField != null)
                    {
                        list.Add(int.Parse(hiddenField.Value));
                    }
                }
            }

            return list;
        }

        /// <summary>
        /// Gets a long id list from the selected CheckBox in the Repeater control.
        /// </summary>
        /// <param name="repeater">The Repeater control.</param>
        /// <param name="checkBoxId">The id of the CheckBox control in the Repeater.</param>
        /// <param name="hiddenFieldId">The id of the HiddenField control in the Repeater which value is related with the CheckBox control.</param>
        /// <returns>A long id list.</returns>
        public static List<long> GetRepeaterSelectedLongId(Repeater repeater, string checkBoxId, string hiddenFieldId)
        {
            List<long> list = new List<long>();
            foreach (RepeaterItem item in repeater.Items)
            {
                CheckBox checkBox = item.FindControl(checkBoxId) as CheckBox;
                if (checkBox != null && checkBox.Checked)
                {
                    HiddenField hiddenField = item.FindControl(hiddenFieldId) as HiddenField;
                    if (hiddenField != null)
                    {
                        list.Add(long.Parse(hiddenField.Value));
                    }
                }
            }

            return list;
        }
    }
}
